home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 102_01.zip / YAHTZEE.C < prev    next >
Text File  |  1993-06-03  |  12KB  |  401 lines

  1.  
  2. /* YAHTZEE Dice game            Steve Ward
  3.  * USAGE:
  4.  *
  5.  *    yahtzee [-dn] name1 name2 name3 ...
  6.  * where the namei are player's names, prefixed by = for automated
  7.  * (computer) players.
  8.  *
  9.  *    yahtzee
  10.  * for solitaire.
  11.  *
  12.  * USE special function keys to select dice, roll selected dice, and end
  13.  *  an inning; keypad up/down arrows select where to enter your score.
  14.  *
  15.  * See YAHTZEE.HLP for full instructions.
  16.  *
  17.  * COMPILE and CLINK with CIO.CRL!
  18.  */
  19.  
  20. #define    ROLLX    39        /* Coordinates for light buttons.    */
  21. #define    OOPSX    46
  22. #define    DONEX    60
  23. #define PASSX    53
  24.  
  25. #define    OOPSC    'P'
  26. #define    DONEC    'R'
  27. #define    ROLLC    'J'
  28. #define PASSC    '!'
  29. #define QUITC    0x03        /* quit the program and return to CP/M    */
  30. #define    GOX    45        /* Coordinates for prompt.        */
  31. #define    GOY    22
  32. #define    GAMEY    20
  33.  
  34. #define    SCOREX    30        /* leftmost column for scores        */
  35. #define    DIEY    22
  36. #define    LABLIN    24        /* Line for labels            */
  37. #define    PLAYERS    10        /* Max number of players        */
  38. #define    NONE    127        /* char-size illegal value.        */
  39.  
  40. char Dice[5];
  41. char nplayers;            /* actual number of players.        */
  42. char Potent[13];        /* Potential score...            */
  43. char PotKind, PotSum, PotStr;    /* Filled by Pot            */
  44. char PotMax, PotCnt;
  45.  
  46. struct Player
  47.  { char Scores[13];        /* Scores, or 127 iff none yet.        */
  48.    char Select;            /* Currently selected category.        */
  49.    char Col;            /* Column number, for scores.        */
  50.    char Name[40];        /* Name of player.            */
  51.    int  Total;            /* total score.                */
  52.    int  Games;
  53.  } Who[PLAYERS];
  54.  
  55. /* Initialize a player:                            */
  56.  
  57. iplayer(name, pl)
  58.  char *name;    struct Player *pl;
  59.  {    char i, *fake;    fake = "==0==";
  60.     if ((!name[1]) && (*name == '=')) { name = fake; name[3]++; }
  61.     for (i=0; i<13; i++) pl->Scores[i] = NONE;
  62.     pl->Select = NONE;
  63.     for (i=0; pl->Name[i] = name[i]; i++); }
  64.  
  65. Buzz() { putchar(7); }
  66. MoveTo(x, y) { puts("\033Y"); putchar(y+32); putchar(x+32); }
  67.  
  68. char ShowX, ShowY, *ShowSc; int ShowTot;
  69.  
  70. Show1(n, flag)
  71.  char n, flag;
  72.  {    int val;
  73.     MoveTo(ShowX, ShowY++);
  74.     if (n == 255) val = ShowTot;    else val = ShowSc[n];
  75.     if (!flag) { puts("\033p");    val = Potent[n]; }
  76.     else if (flag == 44) puts("\033p");
  77.     if (val == NONE) puts("  ? ");
  78.     else { printf("%3d", val); ShowTot += val; }
  79.     if (!flag || (flag == 44)) puts("\033q"); }
  80.  
  81. Show(pl)        /* Show the scores of a player.        */
  82.  char pl;
  83.  {    struct Player *p;
  84.     char cc, tot, f, j;
  85.     Pot(pl);
  86.     ShowX = (p = &Who[pl])->Col-1;    ShowY = 1;    ShowTot = 0;
  87.     ShowSc = p->Scores;    cc = 0;        f = p->Select;
  88.     Show1(cc++,f--);    Show1(cc++,f--);    Show1(cc++,f--);
  89.     Show1(cc++,f--);    Show1(cc++,f--);    Show1(cc++,f--);
  90.     tot = ShowTot;    Show1(255,44);    ShowTot = j = tot>=63? 35:0;
  91.     Show1(255,44);
  92.     tot = ShowTot = tot+j;    Show1(255,44);    ShowTot = tot;
  93.     ShowY++;
  94.     Show1(cc++,f--);    Show1(cc++,f--);    Show1(cc++,f--);
  95.     Show1(cc++,f--);    Show1(cc++,f--);    Show1(cc++,f--);
  96.     Show1(cc++,f--);
  97.     p->Total = ShowTot;
  98.     Show1(255,44); }
  99.  
  100. char Straight(die)    /* Gives longest straight starting at die    */
  101.  {    char i, j;
  102.     for (i=1; i<6; i++)
  103.      { die++;
  104.        for (j=0; j<5; j++) if (Dice[j] == die) goto hit;
  105.        break;
  106.    hit:       continue; }
  107.     return i; }
  108.  
  109. char Kind(die)        /* Gives number of dice of count die        */
  110.  {    char count, i;
  111.     for (i=count=0; i<5; i++) if (die == Dice[i]) count++;
  112.     return count; }
  113.  
  114. Pot(pl)        /* Compute potential scores for player.        */
  115.  char pl;
  116.  {    char i,j,k;
  117.     for (i=0; i<13; i++) Potent[i] = 0;
  118.     for (i=0; i<5; i++) if (((j = Dice[i])>0) && (j<7)) Potent[j-1] += j;
  119.     for (PotMax=PotSum=i=PotKind=0; i<5; i++)
  120.      { PotKind |= (1<<(j=Kind(k=Dice[i]))); PotSum += Dice[i];
  121.        if (j>PotMax) { PotMax=j; PotCnt=k; }}
  122.     Potent[12] = PotSum;
  123.     if ((PotKind & 0xC) == 0xC) Potent[8] = 25;
  124.     if (PotKind & 0x38) Potent[6] = PotSum;
  125.     if (PotKind & 0x30) Potent[7] = PotSum;
  126.     if (PotKind & 0x20) Potent[11] = 50;
  127.     for (i=PotStr=0; i<5; i++) if ((j = Straight(Dice[i])) > PotStr)
  128.         PotStr=j;
  129.     if (PotStr >= 4) Potent[9] = 30;
  130.     if (PotStr == 5) Potent[10] = 40; }
  131.  
  132.  
  133. Play(pl)        /* Make a player's move; returns 0 iff OK. */
  134.  char pl;
  135.  {    Pot(pl);
  136.     Who[pl].Scores[Who[pl].Select] = Potent[Who[pl].Select]; }
  137.  
  138. Bd(f)
  139.  char f;
  140.  {    char i, *cc;
  141.     cc = " . ";
  142.     if (f == 1) { puts("\033F"); cc = "iii"; }
  143.     else if (!f) puts("\033q");
  144.     for (i=((80-SCOREX)/3); i--;) puts(cc);
  145.     puts("\033p\033G\n"); }
  146.  
  147. Board()
  148.  {    char i;
  149.     printf("\033H\033J\033p\033G");
  150.     printf(" H89 YAHTZEE 1.1            \033F");
  151.     for (i=48; i--;) putchar('i'); puts("\033G\n");
  152.     printf("        ACES        ADD 1's "); Bd(0);    /* Y = 1 */
  153.     printf("        TWOS        ADD 2's "); Bd(0);
  154.     printf("        THREES      ADD 3's "); Bd(0);
  155.     printf("        FOURS       ADD 4's "); Bd(0);
  156.     printf("        FIVES       ADD 5's "); Bd(0);
  157.     printf("        SIXES       ADD 6's "); Bd(0);
  158.     printf("   Subtotal  .  .  .  .  .  "); Bd(2);        /* Y = 7 */
  159.     printf("   Bonus iff >= 63       35 ");    Bd(2);        /* Y = 8 */
  160.     printf("TOTAL ABOVE   .  .  .  .  . ");    Bd(2);        /* Y = 9 */
  161.     printf("                            \n");
  162.            printf("        3 of a kind     SUM ");    Bd(0);    /* Y = 11 */
  163.     printf("        4 of a kind     SUM ");    Bd(0);
  164.     printf("        Full House       25 ");    Bd(0);
  165.     printf("        4 Straight       30 ");    Bd(0);
  166.     printf("        5 Straight       40 ");    Bd(0);
  167.     printf("        YAHTZEE          50 ");    Bd(0);
  168.     printf("        Chance          SUM ");    Bd(0);
  169.     printf("TOTAL SCORE   .  .  .  .  . ");    Bd(2);
  170.     MoveTo(0, GAMEY);
  171.     printf("GAMES   .  .  .  .  .  .  . "); Bd(1);
  172.     pscores();
  173.     puts("\033p\033F");
  174.     MoveTo(ROLLX, LABLIN);    puts("i ROLL i");
  175.     MoveTo(DONEX, LABLIN);    puts("i DONE i");
  176.     MoveTo(PASSX, LABLIN);    puts("i      i");
  177.     MoveTo(OOPSX, LABLIN);    puts("i OOPS i");
  178.     puts("\033q\033G");
  179.  }
  180.  
  181. #define    TOP    0
  182. #define    MID    8
  183. #define    BOT    16
  184.  
  185. Die(number, count)
  186.  {    char i, j;
  187.     if (count) puts("\033p\033F");
  188.     for (i=0; i<3; i++)
  189.      { MoveTo(4+(7*number), DIEY+i);
  190.        switch (count+(i<<3))
  191.         {    case TOP: case MID: case BOT:
  192.             case TOP+1: case BOT+1:
  193.             case MID+2:
  194.             case MID+4:    puts("     "); break;
  195.             case TOP+2:
  196.             case TOP+3:    puts("^    "); break;
  197.             case MID+1:
  198.             case MID+3:
  199.             case MID+5:    puts("  ^  "); break;
  200.             case BOT+2:
  201.             case BOT+3:    puts("    ^"); break;
  202.             case TOP+4:    case BOT+4:
  203.             case TOP+5:    case BOT+5:
  204.             case TOP+6:    case MID+6:    case BOT+6:
  205.                     puts("^   ^"); break; }}
  206.     Dice[number] = count;
  207.     puts("\033G\033q"); }
  208.  
  209.  
  210. Roll()
  211.  {    char i;
  212.     for (i=0; i<5; i++) if (!Dice[i]) Die(i, 1+nrand(1)%6); }
  213.  
  214.  
  215. int    DTime;
  216.  
  217. Go(rolls, player)
  218.  char rolls, player;
  219.  {    char ch, i, save[5];
  220.     Pot(player);
  221.     for (i=0; i<5; i++) Dice[i] = 0;    Roll();
  222.     Who[player].Select = 12;
  223.     if (!Cycle(player, 1)) return 0;
  224.  
  225. Top:    for (i=0; i<5; i++) save[i] = Dice[i];
  226. nsc:    Show(player);
  227.     for (;;)
  228.     { MoveTo(GOX, GOY);
  229.       printf("\033q\033G%s's move: %d rolls left. \033K",
  230.         *Who[player].Name == '=' ? Who[player].Name+1 : Who[player].Name,
  231.         rolls);
  232. esc:      if (Who[player].Name[0] == '=') ch = Auto(player, rolls);
  233.       else ch = getchar();
  234.       switch (ch)
  235.       { case 033:    goto esc;
  236.         case '8':    Cycle(player, -1);    Show(player);    continue;
  237.         case ' ':
  238.         case '2':    Cycle(player, 1);    Show(player);    continue;
  239.         case 'S': case 'T': case 'U': case 'V': case 'W':
  240.              if (!rolls) Buzz();
  241.             else Die(ch - 'S', 0); continue;
  242.         case 0177:
  243.         case OOPSC:    for (i=0; i<5; i++) Die(i, save[i]); continue;
  244.         case ROLLC:    if (rolls>0) { Roll(); rolls--; }
  245.             else Buzz(); goto Top;
  246.         case PASSC:
  247.         case DONEC:
  248.         case '\r':    Play(player);
  249.             Who[player].Select = NONE;    Show(player);
  250.                 return ch;
  251.         case QUITC: puts("\33y1\33y5\33q\33E"); exit();
  252.         default:    putchar(7); continue; }}}
  253.  
  254. /* Make move for a computer player:                */
  255.  
  256. int AutoPar[10];    /* Heuristic parameters -HA#, -HB#, etc.    */
  257.  
  258. char Auto(pl, rolls)
  259.  char pl, rolls;
  260.  {    char gofor, choice, i, j, *sc;
  261.     int value[13], target[6], best, n;
  262.     sc = Who[pl].Scores;
  263.     Pot(pl);
  264.     MoveTo(GOX, GOY+1); printf("Hmmm ... lemme think.\033K",
  265.         value[choice]);
  266.     Delay(DTime);
  267.  
  268.     for (i=0; i<13; i++)
  269.      { if (sc[i] != NONE) value[i] = i-99;
  270.        else    if (i<6) value[i] = 2*(Potent[i]-3*(i+1));/* face counts */
  271.        else if (i==6) value[i] = Potent[i]-20;    /* 3 of a kind */
  272.        else if (i==7) value[i] = Potent[i]-15;    /* 4 of a kind */
  273.        else if (i==9) value[i] = Potent[i]-12;    /* 4 straight  */
  274.        else if (i==10) value[i] = Potent[i]-10;    /* 5 straight  */
  275.        else if (i==12) value[i] = Potent[i]-21-AutoPar[5];    /* CHANCE */
  276.        else value[i] = Potent[i]-10; }
  277.  
  278.     for (i=0; i<6; i++)
  279.      { if (sc[12] == NONE) target[i] = i+i; else target[i] = 0;
  280.        if (sc[i] == NONE) target[i] += i<<2; else target[i] -= 15;
  281.        if ((sc[8] == NONE) && (Kind(i+1) == 3)) target[i] += 6;
  282.        if (sc[11] == NONE) target[i] += 1<<(Kind(i+1));
  283.        target[i] += Kind(i+1)<<3; }
  284.  
  285.     best = -99; gofor = PotCnt; choice = Who[pl].Select;
  286.  
  287.     for (i=0; i<13; i++)
  288.      if (value[i] > best) { best = value[i]; choice = i; }
  289.     Who[pl].Select = choice;
  290.     Show(pl);
  291.  
  292.     if (rolls &&        /* Convert a straight??        */
  293.         (Potent[9] > 0) &&
  294.         (Potent[10] == 0) &&
  295.         (sc[10] == NONE))
  296.      { for (i=0; i<5; i++)    /* Find the useless die.    */
  297.         { j = Dice[i];    Dice[i] = 0;    Pot(pl);    Dice[i] = j;
  298.           if (Potent[9] > 0) { Die(i, 0); goto rollit; }}}
  299.     Pot(pl);
  300.     if ((choice > 7) && (choice < 12)) goto hit; /* End the inning.    */
  301.  
  302.     if (rolls)
  303.      { for (i=0; i<6; i++) if ((n=(target[i]-27-AutoPar[0])) > best)
  304.                 { gofor = i; choice = 255; best=n; }}
  305.  
  306.     if ((choice == 255) || (choice < 8)) goto maxim; /*See if we can help*/
  307.  
  308. flush:    if (!rolls) goto hit;        /* Least of evils...    */
  309.     for (i=0; i<5; i++) Die(i,0);    /* Re-roll entire hand.    */
  310.     goto rollit;
  311.  
  312. maxim:    if (!rolls) goto hit;        /* Maximize number of chosen dice. */
  313.     for (i=0; i<5; i++)
  314.      if (Dice[i] && (Dice[i] != (gofor+1))) Die(i, 0);
  315. rollit:    MoveTo(GOX, GOY+1); printf("Baby needs shoes ... %d/%d\033K",
  316.         choice, best);
  317.     Delay(DTime>>1);
  318.     return ROLLC;
  319.  
  320. hit:    MoveTo(GOX, GOY+1); printf("I've decided ... %d/%d\033K",
  321.         choice, best);
  322.     Delay(DTime);
  323.     return PASSC;
  324.  }
  325.  
  326. Delay(n)
  327.  {    while (n--) if (kbhit()) { getchar(); break; }}
  328.  
  329. int Cycle(pl, delta)        /* Move a player's Select ... 0 iff done. */
  330.  char pl; int delta;
  331.  {    char *sel, *sc, done;    int ss;
  332.     ss = *(sel = &(Who[pl].Select));    sc = &(Who[pl].Scores);
  333.     done = 14;
  334.     do    { if ((ss += delta) < 0) ss = 12;
  335.           if (ss >= 13) ss = 0; }
  336.     while (--done && (sc[ss] != NONE));
  337.     *sel = ss;
  338.     return done; }
  339.  
  340. Center(text, centx, y, xsize)
  341.  char *text, centx, y, xsize;
  342.  {    char i;
  343.     for (i=0; text[i]; i++);
  344.     if (i > xsize) i = xsize;
  345.     MoveTo(centx - (i>>1), y);
  346.     putchar(' ');
  347.     while (*text && i--) putchar(*text++);
  348.     putchar(' '); }
  349.  
  350. main(argc, argv)
  351.  char **argv;
  352.  {    char i,j,arg,*carg;    int n, *m;
  353.     for (i=0; i<PLAYERS; i++) Who[i].Games = 0;
  354.     for (i=m=0; i<200; i++) n += *m++;
  355.     nrand(-1,n,n,n);
  356.     for (i=0; i<10; i++) AutoPar[i] = 0;    DTime = 5000;
  357.     TTYMode(28);            /* ^C, FLOW, STRIP, EXPAND */
  358.     puts("\033x1\033q\033G\033y7\033x5");
  359.  
  360.     for (arg=1; (arg<argc) && (*(carg = argv[arg]) == '-'); arg++)
  361.      switch (*++carg)
  362.       { case 'R':    nrand(-1,atoi(++carg)); continue;
  363.         case 'H':    i = (*++carg)-'A';
  364.             AutoPar[i] = atoi(++carg); continue;
  365.         case 'D':    DTime = atoi(++carg)|1; continue;
  366.         default:    continue;
  367.       }
  368. Again:    nplayers = 0;
  369.     for (i=arg; i<argc; i++) iplayer(argv[i], &Who[nplayers++]);
  370.     if (!nplayers) iplayer("You", &Who[nplayers++]);
  371.     n = (80-SCOREX)/nplayers;
  372.     for (i=SCOREX+(n>>1), j=0; j<nplayers; j++, i += n) Who[j].Col = i;
  373.     Board();
  374.     for (j=0; j<nplayers; j++) Center(Who[j].Name, Who[j].Col, 0, n-1);
  375.     for (i=0; i<nplayers; i++) Show(i);
  376.     for (;;) for (i=0; i<nplayers; i++)
  377.         if (!Go(2, i))
  378.             { for (i=n=0; i<nplayers; i++)
  379.                 if (Who[i].Total > n) n = Who[i].Total;
  380.               for (i=0; i<nplayers; i++)
  381.                 if (Who[i].Total >= n)
  382.                      ++(Who[i].Games);
  383.               pscores();
  384.               MoveTo(GOX, GOY+1);
  385.               for (i=0; i<nplayers; i++)
  386.                 if (Who[i].Total >= n)
  387.                    printf("%s ", Who[i].Name);
  388.               printf("\007WINS! \033q Play again? \033K");
  389.               if (getchar() == 'y') goto Again;
  390.               puts("\033Y6 \033J\033y5\033y1\033q\033G");
  391.               exit(); }
  392.  }
  393.  
  394. pscores()
  395. {
  396.     int i;
  397.     for (i=0; i<nplayers; i++)
  398.      { MoveTo(Who[i].Col, GAMEY);
  399.        printf("\033p%3d", (Who[i].Games)); }
  400. }
  401.